# -*- coding: utf-8 -*-
import os
import shlex
from pathlib import Path
import socket
import warnings
from PySide2.QtCore import QThread, Signal
from gglobal import logger, config
from mooetoolapp.handlercore.paramikomodel import Server
from mooetoolapp.handlercore.file_parser import FileParser
from mooetoolapp.handlercore.connection_manager import ConnectionStateManager
from mooetoolapp.handlercore.language_manager import LanguageManager
from mooetoolapp.handlercore.cmderrcheck import CommandErrorChecker

# Suppress warnings from paramiko
warnings.filterwarnings(action="ignore", module=".*paramiko.*")


class ClientCarThread(QThread):
    """车辆连接线程类"""
    
    # 信号定义
    connection_status = Signal(bool, str)  # 连接状态信号 (成功/失败, 消息)
    command_output = Signal(str)  # 命令输出信号
    file_list_updated = Signal(list)  # 文件列表更新信号

    current_path_changed = Signal(str)  # 当前路径变化信号
    
    # 新增高级传输进度信号
    transfer_progress = Signal(str, int, int, float)  # 传输进度信号 (文件名, transferred, total, speed)

    
    def __init__(self, ip_address, parent=None):
        super().__init__(parent)
        self.ip = ip_address
        self.ssh_client = None
        # 使用统一的连接状态管理器
        self._connection_manager = ConnectionStateManager(self)
        self._connection_manager.connection_status_changed.connect(self.connection_status.emit)
        self.in_docker_container = False
        
        # 从配置获取连接参数
        self.port = config.get_param('port', 22)
        self.username = config.get_param('username', '')
        self.password = config.get_param('password', '')
        self.ssh_remote_folder = config.get_param('ssh_remote_folder', '/mooe/log')
        
        # 获取语言管理器实例
        self.language_manager = LanguageManager.get_instance()
        
        # 连接取消标志
        self._connection_cancelled = False
        
        # 远程主机当前路径维护
        self.current_remote_path = None
        

        
    def run(self):
        """线程主函数 - 建立连接"""
        try:
            self.connect_to_vehicle()
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('connection_thread_error')}: {str(e)}"
            logger.error(error_msg)
            self._connection_manager.set_connected(False, message=f"{self.language_manager.get_constant('connection_exception')}: {str(e)}")
    
    def connect_to_vehicle(self):
        """连接到车辆 - 使用统一的connect_manage函数"""
        try:
            # 检查连接是否被取消
            if self._connection_cancelled:
                cancel_msg = self.language_manager.get_constant('connection_cancelled', '连接已取消')
                self._connection_manager.set_connected(False, message=cancel_msg)
                return
            
            logger.info(f"{self.language_manager.get_constant('connection_start')}: {self.ip}:{self.port}")
            
            # 创建SSH连接实例
            self.ssh_client = Server(
                ip=self.ip,
                port=self.port,
                username=self.username,
                password=self.password
            )
            
            # 使用统一的连接管理函数进行完整连接
            result = self.ssh_client.connect_manage(
                check=True,           # 检查端口连通性
                connect=True,         # 建立SSH连接
                sshopen=True,         # 开启SSH服务
                sftpopen=True,        # 开启SFTP服务
                channel=True,         # 开启交互式Channel
                expect_symbol="$ ",   # 期望的提示符
                port_timeout=5,       # 端口检查超时时间
                cancellation_callback=lambda: self._connection_cancelled  # 取消回调
            )
            
            # 记录详细的连接步骤结果
            logger.info(f"连接管理结果: {result['success']} - {result['message']}")
            for step, detail in result['details'].items():
                logger.info(f"步骤 {step}: {detail['success']} - {detail['message']}")
            
            # 检查连接是否成功
            if result['success']:
                # 连接成功
                success_msg = f"{self.language_manager.get_constant('connection_success')} {self.ip}"
                self._connection_manager.set_connected(True, self.ip, success_msg)
                logger.info(success_msg)
            else:
                # 连接失败，根据失败的步骤提供具体的错误信息
                failed_step = None
                for step, detail in result['details'].items():
                    if not detail['success']:
                        failed_step = step
                        break
                
                # 根据失败步骤设置相应的错误消息
                if failed_step == 'port_check':
                    error_msg = f"{self.language_manager.get_constant('connection_failed_port')} {self.ip}:{self.port}"
                elif failed_step == 'ssh_connect':
                    error_msg = f"{self.language_manager.get_constant('ssh_connection_failed')}: {result['message']}"
                elif failed_step == 'ssh_open':
                    error_msg = f"{self.language_manager.get_constant('ssh_service_failed')}: {result['message']}"
                elif failed_step == 'sftp_open':
                    error_msg = f"{self.language_manager.get_constant('sftp_service_failed')}: {result['message']}"
                elif failed_step == 'channel_open':
                    error_msg = f"{self.language_manager.get_constant('channel_failed')}: {result['message']}"
                elif failed_step == 'prompt_get':
                    error_msg = f"{self.language_manager.get_constant('prompt_failed')}: {result['message']}"
                else:
                    error_msg = f"{self.language_manager.get_constant('connection_failed')}: {result['message']}"
                
                self._connection_manager.set_connected(False, message=error_msg)
                logger.error(error_msg)
            
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('connection_failed')}: {str(e)}"
            logger.error(error_msg)
            self._connection_manager.set_connected(False, message=error_msg)
    
    def _check_port_connectivity(self):
        """检查端口连通性 - 已迁移到paramikomodel.py的connect_manage函数中
        
        此方法保留用于向后兼容，但建议使用connect_manage函数
        """
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(5)
            s.connect((self.ip, self.port))
            s.close()
            return True
        except (socket.timeout, ConnectionRefusedError, OSError):
            return False
    

    
    def execute_command_callback(self, decoded_data, callback_func=None):
        """通用回调方法"""
        if callback_func:
            callback_func(decoded_data)
        else:
            # 默认处理：发送信号
            self.command_output.emit(decoded_data.strip())
            logger.info(decoded_data.strip())
    
    def _normalize_remote_path(self, file_path):
        """规范化远程路径处理"""
        if not file_path:
            return self.current_remote_path or '/'
        
        # 将Windows路径分隔符转换为Unix路径分隔符
        file_path = file_path.replace('\\', '/')
        
        # 如果已经是绝对路径，直接返回
        if file_path.startswith('/'):
            return file_path
        
        # 如果是相对路径，拼接当前路径
        if self.current_remote_path:
            if self.current_remote_path == '/':
                return f"/{file_path}"
            else:
                return f"{self.current_remote_path}/{file_path}"
        else:
            # 如果没有当前路径，默认使用根目录
            return f"/{file_path}"
    
    def get_current_working_directory(self):
        """获取当前工作目录（pwd命令）"""
        if not self._connection_manager.is_connected or not self.ssh_client:
            logger.error(self.language_manager.get_constant('vehicle_not_connected'))
            return None
        
        try:
            result = self.ssh_client.channel_send_cmd("pwd", timeout=5)
            # 清理结果，去除命令回显和提示符
            lines = result.strip().split('\n')
            for line in lines:
                line = line.strip()
                # 跳过命令回显和提示符
                if line and not line.startswith('pwd') and not line.endswith('$') and not line.endswith('#'):
                    if line.startswith('/'):
                        logger.info(f"当前工作目录: {line}")
                        return line
            return None
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('get_pwd_failed', '获取当前目录失败')}: {str(e)}"
            logger.error(error_msg)
            return None
    
    def change_directory(self, path):
        """通用cd命令"""
        if not self._connection_manager.is_connected or not self.ssh_client:
            logger.error(self.language_manager.get_constant('vehicle_not_connected'))
            return False
        
        try:
            cmd = f"cd {path}"
            result = self.ssh_client.channel_send_cmd(cmd, timeout=8)
            logger.info(f"切换目录到 {path}: {result}")
            
            # 使用统一的命令错误检查
            success, error_msg = CommandErrorChecker.check_cd_result(result)
            if not success:
                logger.error(f"cd命令失败: {error_msg}")
                return False
            
            # cd成功后更新当前路径
            updated_path = self.get_current_working_directory()
            if updated_path:
                self.current_remote_path = updated_path
                logger.info(f"当前路径已更新为: {self.current_remote_path}")
                # 发出路径变化信号
                self.current_path_changed.emit(self.current_remote_path)
                return True
            else:
                logger.error("cd命令执行后无法获取当前路径，可能失败")
                return False
            
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('change_directory_failed')}: {str(e)}"
            logger.error(error_msg)
            return False
    
    def list_directory(self, path=None, detailed=True):
        """通用ls命令"""
        if not self._connection_manager.is_connected or not self.ssh_client:
            logger.error(self.language_manager.get_constant('vehicle_not_connected'))
            return []
        
        try:
            # 如果未传入路径，使用当前维护的路径
            if path is None:
                if self.current_remote_path:
                    path = self.current_remote_path
                else:
                    path = "."
            
            cmd = "ls -la" if detailed else "ls"
            if path != ".":
                cmd += f" {path}"
            
            result = self.ssh_client.channel_send_cmd(cmd, timeout=8)
            logger.info(f"列出目录 {path} 内容: {result}")
            # 使用统一的文件解析器，传入实际的当前路径
            current_path = self.current_remote_path if self.current_remote_path else path
            files = FileParser.parse_ls_output(result, current_path)
            valid_files = FileParser.filter_valid_files(files)
            self.file_list_updated.emit(valid_files)
            return valid_files
            
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('list_directory_failed')}: {str(e)}"
            logger.error(error_msg)
            return []
    
    # 移除重复的文件解析方法，统一使用FileParser
    
    def remove_file(self, file_path):
        """通用rm命令"""
        if not self._connection_manager.is_connected or not self.ssh_client:
            logger.error(self.language_manager.get_constant('vehicle_not_connected'))
            return False
        
        try:
            # 规范化路径处理
            full_path = self._normalize_remote_path(file_path)
            
            cmd = f"rm -rf {full_path}"
            result = self.ssh_client.channel_send_cmd(cmd, timeout=15)
            logger.info(f"删除文件 {full_path}: {result}")
            
            # 使用统一的命令错误检查
            success, error_msg = CommandErrorChecker.check_delete_result(result)
            if not success:
                logger.error(f"删除文件失败: {error_msg}")
                return False
            
            return True
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('delete_file_failed')}: {str(e)}"
            logger.error(error_msg)
            return False
    
    def download_file(self, remote_path, local_path, use_advanced=True, chunk_size=65536, resume=True):
        """SFTP下载文件
        
        Args:
            remote_path: 远程文件路径
            local_path: 本地文件路径
            use_advanced: 是否使用高级下载功能（支持进度显示、断点续传等）
            chunk_size: 分块大小（字节），默认64KB
            resume: 是否启用断点续传
        """
        if not self._connection_manager.is_connected or not self.ssh_client:
            logger.error(self.language_manager.get_constant('vehicle_not_connected'))
            return False
        
        try:
            # 规范化远程路径
            full_remote_path = self._normalize_remote_path(remote_path)
            filename = os.path.basename(full_remote_path)
            
            if use_advanced:
                # 使用高级下载功能
                def progress_callback(transferred, total, speed):
                    """进度回调函数"""
                    # 发送详细的传输进度信号
                    self.transfer_progress.emit(filename, transferred, total, speed)
                
                result = self.ssh_client.sftp_get_advanced(
                    remotefile=full_remote_path,
                    localfile=local_path,
                    chunk_size=chunk_size,
                    resume=resume,
                    progress_callback=progress_callback
                )
                
                logger.info(f"高级下载文件结果: {result}")
                
                if result['success']:
                    success_msg = f"下载成功: {self.ssh_client.format_size(result['total_size'])}, 平均速度: {self.ssh_client.format_speed(result['speed'])}, 耗时: {result.get('elapsed_time', 0):.2f}秒"
                    logger.info(success_msg)
                    return True
                else:
                    error_msg = f"下载失败: {result['message']}"
                    logger.error(error_msg)
                    return False
            else:
                # 使用原始下载功能（向后兼容）
                result = self.ssh_client.sftp_get(full_remote_path, local_path)
                logger.info(f"下载文件结果: {result}")
                
                # 使用统一的命令错误检查
                success, error_msg = CommandErrorChecker.check_transfer_result(result)
                if not success:
                    logger.error(f"下载文件失败: {error_msg}")
                    return False
                
                return True
                
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('download_file_failed')}: {str(e)}"
            logger.error(error_msg)
            return False

    def download_file_direct(self, remote_path: str, local_path: str) -> bool:
        """使用原始SFTP直接下载（paramikomodel.sftp_get）

        目的：
        - 排除高级SFTP下载在某些设备上导致断开连接的风险；
        - 简化下载流程，仅依赖底层 `sftp_get`。

        参数：
        - remote_path: 远程文件路径（相对或绝对，函数内部统一规范化）。
        - local_path: 本地文件绝对路径。

        返回：
        - bool: 下载是否成功。
        """
        # 基本连接校验，避免空指针与未连接风险
        if not self._connection_manager.is_connected or not self.ssh_client:
            logger.error(self.language_manager.get_constant('vehicle_not_connected'))
            return False

        try:
            # 规范化远程路径，统一为POSIX风格，防止路径异常
            full_remote_path = self._normalize_remote_path(remote_path)

            # 调用底层原始SFTP下载
            result_str = self.ssh_client.sftp_get(full_remote_path, local_path)
            logger.info(f"直接下载文件结果: {result_str}")

            # 使用统一的命令结果检查器进行判定
            success, error_msg = CommandErrorChecker.check_transfer_result(result_str)
            if not success:
                logger.error(f"直接下载文件失败: {error_msg}")
                return False
            return True
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('download_file_failed')}: {str(e)}"
            logger.error(error_msg)
            return False
    

    def upload_file_detail(self, local_path, remote_path, use_advanced=True, chunk_size=65536, resume=True):
        """SFTP上传文件（返回详细结果字典）
        
        Args:
            local_path: 本地文件路径
            remote_path: 远程文件路径
            use_advanced: 是否使用高级上传功能（支持进度显示、断点续传等）
            chunk_size: 分块大小（字节），默认64KB
            resume: 是否启用断点续传
        
        Returns:
            dict: 包含success、message等的详细结果
        """
        if not self._connection_manager.is_connected or not self.ssh_client:
            err = self.language_manager.get_constant('vehicle_not_connected')
            logger.error(err)
            return {"success": False, "message": err}
        
        try:
            # 规范化远程路径
            full_remote_path = self._normalize_remote_path(remote_path)
            filename = os.path.basename(local_path)
            
            if use_advanced:
                # 使用高级上传功能，直接返回底层的结构化结果
                def progress_callback(transferred, total, speed):
                    self.transfer_progress.emit(filename, transferred, total, speed)
                
                result = self.ssh_client.sftp_put_advanced(
                    localfile=local_path,
                    remotefile=full_remote_path,
                    chunk_size=chunk_size,
                    resume=resume,
                    progress_callback=progress_callback
                )
                logger.info(f"高级上传文件结果: {result}")
                return result
            else:
                # 使用原始上传功能，封装为结构化结果
                raw = self.ssh_client.sftp_put(local_path, full_remote_path)
                logger.info(f"上传文件结果: {raw}")
                success, error_msg = CommandErrorChecker.check_transfer_result(raw)
                return {
                    "success": success,
                    "message": (error_msg if not success else "ok"),
                    "raw_result": raw
                }
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('upload_file_failed')}: {str(e)}"
            logger.error(error_msg)
            return {"success": False, "message": str(e)}

    def upload_file_direct(self, local_path: str, remote_path: str) -> bool:
        """使用原始SFTP直接上传（paramikomodel.sftp_put）

        目的：
        - 排除高级SFTP上传在某些设备上导致断开连接的风险；
        - 简化上传流程，仅依赖底层 `sftp_put`。

        参数：
        - local_path: 本地文件绝对路径。
        - remote_path: 远程文件路径（相对或绝对，函数内部统一规范化）。

        返回：
        - bool: 上传是否成功。
        """
        # 基本连接校验，避免空指针与未连接风险
        if not self._connection_manager.is_connected or not self.ssh_client:
            err = self.language_manager.get_constant('vehicle_not_connected')
            logger.error(err)
            return False

        try:
            # 规范化远程路径，统一为POSIX风格，防止路径异常
            full_remote_path = self._normalize_remote_path(remote_path)

            # 调用底层原始SFTP上传
            result_str = self.ssh_client.sftp_put(localfile=local_path, remotefile=full_remote_path)
            logger.info(f"直接上传文件结果: {result_str}")

            # 使用统一的命令结果检查器进行判定
            success, error_msg = CommandErrorChecker.check_transfer_result(result_str)
            if not success:
                logger.error(f"直接上传文件失败: {error_msg}")
                return False
            return True
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('upload_file_failed')}: {str(e)}"
            logger.error(error_msg)
            return False
    
    def send_ctrl_c(self):
        """执行Ctrl+C命令"""
        if not self._connection_manager.is_connected or not self.ssh_client:
            logger.error(self.language_manager.get_constant('vehicle_not_connected'))
            return False
        
        try:
            # 发送Ctrl+C信号
            if self.ssh_client._channel:
                self.ssh_client._channel.send("\x03")  # Ctrl+C的ASCII码
                logger.info(self.language_manager.get_constant('ctrl_c_sent'))
                return True
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('ctrl_c_failed')}: {str(e)}"
            logger.error(error_msg)
            return False
    
    def compress_file(self, file_path, compression_type="tar.gz"):
        """通用压缩命令"""
        if not self._connection_manager.is_connected or not self.ssh_client:
            logger.error(self.language_manager.get_constant('vehicle_not_connected'))
            return False
        
        try:
            # 规范化文件路径
            original_file_path = file_path
            # 保持原始路径用作远程路径（该路径应为Linux风格，如 /mooe/...）
            full_file_path = file_path

            # 解析父目录与目标名，先切换到父目录再执行压缩，避免压缩包内出现多层目录结构
            try:
                p = Path(full_file_path)
                parent_dir = str(p.parent).replace('\\', '/')  # 统一为POSIX分隔符
                target_name = p.name
            except Exception:
                # 兜底：字符串切割
                if '/' in full_file_path:
                    parent_dir = full_file_path.rsplit('/', 1)[0]
                    target_name = full_file_path.rsplit('/', 1)[1]
                else:
                    parent_dir = '.'
                    target_name = full_file_path

            q_parent = shlex.quote(parent_dir)
            q_target = shlex.quote(target_name)

            if compression_type == "zip":
                out_name = shlex.quote(f"{target_name}.zip")
                cmd = f"cd {q_parent} && zip -r {out_name} {q_target}"
            elif compression_type == "tar":
                out_name = shlex.quote(f"{target_name}.tar")
                cmd = f"cd {q_parent} && tar -cf {out_name} {q_target}"
            elif compression_type == "tar.gz":
                out_name = shlex.quote(f"{target_name}.tar.gz")
                cmd = f"cd {q_parent} && tar -czf {out_name} {q_target}"
            elif compression_type == "gz":
                # 单文件压缩，仍先进入父目录以保持输出在父目录
                cmd = f"cd {q_parent} && gzip {q_target}"
            else:
                error_msg = f"{self.language_manager.get_constant('unsupported_compression_format')}: {compression_type}"
                logger.error(error_msg)
                return False
            
            result = self.ssh_client.channel_send_cmd(cmd, timeout=60)
            logger.info(f"压缩命令执行结果 {original_file_path}: {result}")
            
            # 使用统一的命令错误检查
            success, error_msg = CommandErrorChecker.check_compress_result(result)
            if not success:
                logger.error(f"压缩文件失败: {error_msg}")
                return False
            
            logger.info(f"{self.language_manager.get_constant('compress_file_success')} {original_file_path}")
            return True
            
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('compress_file_failed')}: {str(e)}"
            logger.error(error_msg)
            return False
    
    def decompress_file(self, file_path, target_dir=None):
        """通用解压命令"""
        if not self._connection_manager.is_connected or not self.ssh_client:
            logger.error(self.language_manager.get_constant('vehicle_not_connected'))
            return False
        
        try:
            # 规范化文件路径和目标目录
            original_file_path = file_path
            full_file_path = self._normalize_remote_path(file_path)
            
            # 规范化目标目录路径
            if target_dir:
                target_dir = self._normalize_remote_path(target_dir)
            
            # 根据文件扩展名确定解压命令
            if full_file_path.endswith(".zip"):
                cmd = f"unzip {full_file_path}"
                if target_dir:
                    cmd += f" -d {target_dir}"
            elif full_file_path.endswith(".tar.gz") or full_file_path.endswith(".tgz"):
                cmd = f"tar -xzf {full_file_path}"
                if target_dir:
                    cmd += f" -C {target_dir}"
            elif full_file_path.endswith(".tar"):
                cmd = f"tar -xf {full_file_path}"
                if target_dir:
                    cmd += f" -C {target_dir}"
            elif full_file_path.endswith(".gz"):
                cmd = f"gunzip {full_file_path}"
            else:
                error_msg = f"{self.language_manager.get_constant('unsupported_decompression_format')}: {original_file_path}"
                logger.error(error_msg)
                return False
            
            result = self.ssh_client.channel_send_cmd(cmd, timeout=60)
            logger.info(f"解压命令执行结果 {original_file_path}: {result}")
            
            # 使用统一的命令错误检查
            success, error_msg = CommandErrorChecker.check_decompress_result(result)
            if not success:
                logger.error(f"解压文件失败: {error_msg}")
                return False
            
            logger.info(f"{self.language_manager.get_constant('decompress_file_success')} {original_file_path}")
            return True
            
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('decompress_file_failed')}: {str(e)}"
            logger.error(error_msg)
            return False
    
    def enter_docker_container(self, container_name="mooe-core"):
        """进入Docker容器"""
        if not self._connection_manager.is_connected or not self.ssh_client:
            logger.error(self.language_manager.get_constant('vehicle_not_connected'))
            return False
        
        try:
            cmd = f"docker exec -it {container_name} /bin/bash"
            result = self.ssh_client.channel_send_cmd(cmd, "$ ")
            logger.info(f"Docker容器进入命令执行结果 {container_name}: {result}")
            
            # 使用统一的命令错误检查
            success, error_msg = CommandErrorChecker.check_docker_result(result)
            if not success:
                logger.error(f"进入Docker容器失败: {error_msg}")
                return False
            
            self.in_docker_container = True
            logger.info(f"{self.language_manager.get_constant('enter_container_success')} {container_name}")
            return True
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('enter_container_failed')}: {str(e)}"
            logger.error(error_msg)
            return False
    
    def exit_docker_container(self):
        """退出Docker容器"""
        if not self._connection_manager.is_connected or not self.ssh_client or not self.in_docker_container:
            return False
        
        try:
            result = self.ssh_client.channel_send_cmd("exit", "$ ")
            logger.info(f"Docker容器退出命令执行: {result}")
            
            # 使用统一的命令错误检查
            success, error_msg = CommandErrorChecker.check_docker_result(result)
            if not success:
                logger.error(f"退出Docker容器失败: {error_msg}")
                return False
            
            self.in_docker_container = False
            logger.info(f"{self.language_manager.get_constant('exit_container_success')}")
            return True
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('exit_container_failed')}: {str(e)}"
            logger.error(error_msg)
            return False

    def close_channel(self):
        """关闭当前SSH通道（仅关闭channel，不断开transport与整体连接）"""
        if not self._connection_manager.is_connected or not self.ssh_client:
            logger.error(self.language_manager.get_constant('vehicle_not_connected'))
            return False
        try:
            channel = getattr(self.ssh_client, "_channel", None)
            # 仅在通道存在且未关闭时执行
            if channel and not getattr(channel, "closed", False):
                try:
                    channel.close()
                except Exception:
                    # 即使关闭抛错，也不影响整体连接；记录日志即可
                    pass
                logger.info("SSH通道已关闭（保留transport与会话）")
                return True
            return False
        except Exception as e:
            logger.error(f"关闭通道失败: {str(e)}")
            return False
    
    def execute_long_command(self, cmd, callback=None, timeout=30):
        """执行长时间运行的命令"""
        if not self._connection_manager.is_connected or not self.ssh_client:
            logger.error(self.language_manager.get_constant('vehicle_not_connected'))
            return False
        
        try:
            def default_callback(data):
                self.command_output.emit(data.strip())
            
            callback_func = callback or default_callback
            
            result = self.ssh_client.channel_send_cmd(
                cmd, 
                long=True, 
                timeout=timeout,
                callback=callback_func
            )
            
            # 对于长时间运行的命令，检查最终结果
            if result:
                logger.info(f"长时间命令执行结果: {result}")
                success, error_msg = CommandErrorChecker.check_command_result(result, "general")
                if not success:
                    logger.error(f"长时间命令执行失败: {error_msg}")
                    return False
            
            return True
            
        except Exception as e:
            error_msg = f"{self.language_manager.get_constant('long_command_failed')}: {str(e)}"
            logger.error(error_msg)
            return False
    
    def execute_custom_command(self, command, timeout=30, emit_signal=True):
        """
        通用命令执行功能
        
        Args:
            command (str): 要执行的命令
            timeout (int): 命令执行超时时间，默认30秒
            emit_signal (bool): 是否通过信号发送输出结果，默认True
            
        Returns:
            tuple: (success: bool, result: str) 执行成功状态和结果
        """
        if not self._connection_manager.is_connected or not self.ssh_client:
            error_msg = self.language_manager.get_constant('vehicle_not_connected', '车辆未连接')
            logger.error(error_msg)
            if emit_signal:
                self.command_output.emit(error_msg)
            return False, error_msg
        
        try:
            logger.info(f"执行自定义命令: {command}")
            
            # 执行命令
            result = self.ssh_client.channel_send_cmd(command, timeout=timeout)
            
            # 记录执行结果
            logger.debug(f"命令执行结果: {result}")
            
            # 通过信号发送结果（如果启用）
            if emit_signal:
                self.command_output.emit(result.strip())
            
            # 使用统一的命令错误检查
            success, error_msg = CommandErrorChecker.check_command_result(result, "general")
            
            if not success:
                logger.error(f"命令执行失败: {error_msg}")
                if emit_signal:
                    self.command_output.emit(f"错误: {error_msg}")
                return False, error_msg
            
            return True, result.strip()
            
        except Exception as e:
            error_msg = f"命令执行异常: {str(e)}"
            logger.error(error_msg)
            if emit_signal:
                self.command_output.emit(error_msg)
            return False, error_msg

    def disconnect_from_vehicle(self):
        """断开车辆连接（兼容方法名）"""
        self.disconnect()
    
    def get_current_remote_path(self):
        """获取当前维护的远程路径"""
        return self.current_remote_path
    
    def disconnect(self, *args, **kwargs):
        """断开连接
        
        - 兼容旧调用方式，同时支持通过关键字参数控制断开类型。
        - 当 `is_manual=False` 时，连接状态消息将为“连接已断开”。
        
        参数：
            *args: 兼容占位参数（忽略）
            **kwargs: 可选关键字参数，如 `is_manual`
        """
        try:
            # 读取是否为手动断开标志（默认True，保持向后兼容）
            is_manual = kwargs.pop('is_manual', True)

            # 设置取消标志
            self._connection_cancelled = True
            
            if self.in_docker_container:
                self.exit_docker_container()
            
            if self.ssh_client:
                result = self.ssh_client.close()
                logger.info(result)
                self.ssh_client = None
            
            # 重置当前路径
            self.current_remote_path = None
            
            # 根据标志更新连接状态消息
            self._connection_manager.disconnect(is_manual=is_manual)
            
        except Exception as e:
            logger.error(f"断开连接失败: {str(e)}")
    
    def __del__(self):
        """析构函数"""
        if self._connection_manager.is_connected:
            # 析构阶段避免误报“手动断开”，统一使用自动断开语义
            self.disconnect(is_manual=False)